/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */

package backupit.core.dirbackup.io;


import backupit.core.BackupInfo;
import backupit.core.io.FileInfoSetWriter;
import backupit.core.io.FileInfoSetReader;
import backupit.core.FileInfoSet;
import backupit.core.dirbackup.DirBackup;
import backupit.core.dirbackup.DirBackupInfo;
import backupit.core.FileInfoComparator;
import backupit.core.DefaultFileInfoComparator;
import backupit.core.io.BackupWriter;
import java.io.File;
import java.io.IOException;
import java.util.logging.Level;
import java.util.logging.Logger;

/**
 *
 * @author dbotelho
 */
public class DirBackupWriter extends BackupWriter {
    
    protected DirBackupInfo backupInfo;
    protected File source_dir;
    protected File dest_dir;
    //private FileInfoSetReader sourceReader;
    //private FileInfoSetReader destinationReader;
    //private FileInfoSet writtenFiles;
    private FileInfoSetWriter writer;
    
    public DirBackupWriter(DirBackup backup) throws IOException{
        super(backup);
        this.setBackupInfo(new DirBackupInfo(backup));
        source_dir = new File(backup.getSource().getIdentifier());
        if (!source_dir.isDirectory()) 
            throw new java.io.IOException(backup.getSource() + "' is not a valid directory!");

        
        dest_dir = new File(backup.getDestination().getIdentifier());
        if (!dest_dir.isDirectory()) {
            if (!dest_dir.exists()) {
                if (dest_dir.mkdir()) {
                    return;
                }
            }
            throw new java.io.IOException(backup.getDestination() + "' is not a valid directory!");
        }
    }
    
    private FileInfoSet read(FileInfoSetReader reader){
        System.out.println("Start reading on: " + reader.getRoot());
        FileInfoSet files = reader.loadFiles();
        System.out.println("Finnished reading on: " + reader.getRoot() + " (" + files.size() + ")");
        return files;
    }

    public long writeBackup(FileInfoSet writtenFiles) throws IOException {
        long bytes = getWriter().write(writtenFiles);
        System.out.println("Number of bytes: " + bytes);
        return bytes;
    }

 

    public void run() {
        
        getSourceFiles();
        
        getDestinationFiles();
        
        //getReport();
        FileInfoSet writtenFiles = getDiffFileInfoset();

        //System.out.println(getReport().getSummaryDiffsToString());
        if (!this.getBackup().getSimulate()) {
            try {
                writeBackup(writtenFiles);
                this.getBackupInfo().setWrittenFiles(writtenFiles);
            } catch (IOException ex) {
                Logger.getLogger(DirBackupWriter.class.getName()).log(Level.SEVERE, null, ex);
            }
        }
        
        //this.setBackupInfo(new DirBackupInfo(backup, getSourceFiles(), getDestinationFiles(), getReport()));

    }
    

    public DirBackupInfo getBackupInfo() {
        return (DirBackupInfo)this.backupInfo;
        /*if(backupInfo!=null)
            return backupInfo;
        else{
            try {
                Thread t = new Thread(this);
                t.start();
                t.join();
                return this.backupInfo;
            } catch (InterruptedException ex) {
                Logger.getLogger(DirBackupWriter.class.getName()).log(Level.SEVERE, null, ex);
                return null;
            }
        }*/
    }

    public FileInfoSet getSourceFiles() {

        if (this.getBackupInfo().getSourceFiles() == null) {
            FileInfoSetReader sourceReader = new FileInfoSetReader(source_dir.getPath(), this.getBackup().getUpdate(), this.getBackup().getHidden(), this.getBackup().getRecursive());
            this.getBackupInfo().setSourceReaderStartTime(System.currentTimeMillis());
            this.getBackupInfo().setSourceFiles(this.read(sourceReader));
            this.getBackupInfo().setSourceReaderEndTime(System.currentTimeMillis());
        }
        return this.getBackupInfo().getSourceFiles();
    }

    public FileInfoSet getDestinationFiles() {
        if (this.getBackupInfo().getDestinationFiles() == null) {
            FileInfoSetReader destinationReader = new FileInfoSetReader(dest_dir.getPath(), this.getBackup().getUpdate(), this.getBackup().getHidden(), this.getBackup().getRecursive());
            this.getBackupInfo().setDestinationReaderStartTime(System.currentTimeMillis());
            this.getBackupInfo().setDestinationFiles(this.read(destinationReader));
            this.getBackupInfo().setDestinationReaderEndTime(System.currentTimeMillis());
        }
        return this.getBackupInfo().getDestinationFiles();
    }
    
    protected FileInfoSet diff(FileInfoComparator comparator,FileInfoSet source, FileInfoSet dest){
        FileInfoSet diffs = (comparator==null) ? new FileInfoSet():new FileInfoSet(comparator);
        
        diffs.addAll(source);
        diffs.removeAll(dest);
        
        return diffs;
    }
/*
    public DifferentFilesReport getReport() {
        if (report == null) {
            DefaultFileInfoComparator comparator = new DefaultFileInfoComparator(this.backup.getUpdate());
            report = new DifferentFilesReport(comparator, getSourceFiles(), getDestinationFiles());
        }
        return report;
    }*/

    /*protected FileInfoSetReader getDestinationReader() {
        if(destinationReader == null)
            destinationReader = new FileInfoSetReader(dest_dir.getPath(), this.getBackup().getUpdate(), this.getBackup().getHidden(), this.getBackup().getRecursive());
            
        return destinationReader;
    }*/


    public FileInfoSetWriter getWriter() {
        if(writer == null)
            writer = new FileInfoSetWriter(dest_dir.getPath());
        return writer;
    }

    public void setWriter(FileInfoSetWriter writer) {
        this.writer = writer;
    }

    public FileInfoSet getDiffFileInfoset() {

            DefaultFileInfoComparator comparator = new DefaultFileInfoComparator(this.getBackup().getUpdate());
            return diff(comparator, this.getBackupInfo().getSourceFiles(), this.getBackupInfo().getDestinationFiles());
    }

    @Override
    public DirBackup getBackup() {
        return (DirBackup)backup;
    }

    @Override
    protected void setBackupInfo(BackupInfo backupInfo) {
        this.backupInfo = (DirBackupInfo)backupInfo;
    }


}
